<!doctype html>
<html>
<head>
<meta charset='UTF-8'><meta name='viewport' content='width=device-width initial-scale=1'>

<style type='text/css'>html {overflow-x: initial !important;}:root { --bg-color:#ffffff; --text-color:#333333; --select-text-bg-color:#B5D6FC; --select-text-font-color:auto; --monospace:"Lucida Console",Consolas,"Courier",monospace; --title-bar-height:20px; }
.mac-os-11 { --title-bar-height:28px; }
html { font-size: 14px; background-color: var(--bg-color); color: var(--text-color); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
body { margin: 0px; padding: 0px; height: auto; inset: 0px; font-size: 1rem; line-height: 1.42857; overflow-x: hidden; background: inherit; tab-size: 4; }
iframe { margin: auto; }
a.url { word-break: break-all; }
a:active, a:hover { outline: 0px; }
.in-text-selection, ::selection { text-shadow: none; background: var(--select-text-bg-color); color: var(--select-text-font-color); }
#write { margin: 0px auto; height: auto; width: inherit; word-break: normal; overflow-wrap: break-word; position: relative; white-space: normal; overflow-x: visible; padding-top: 36px; }
#write.first-line-indent p { text-indent: 2em; }
#write.first-line-indent li p, #write.first-line-indent p * { text-indent: 0px; }
#write.first-line-indent li { margin-left: 2em; }
.for-image #write { padding-left: 8px; padding-right: 8px; }
body.typora-export { padding-left: 30px; padding-right: 30px; }
.typora-export .footnote-line, .typora-export li, .typora-export p { white-space: pre-wrap; }
.typora-export .task-list-item input { pointer-events: none; }
@media screen and (max-width: 500px) {
  body.typora-export { padding-left: 0px; padding-right: 0px; }
  #write { padding-left: 20px; padding-right: 20px; }
  .CodeMirror-sizer { margin-left: 0px !important; }
  .CodeMirror-gutters { display: none !important; }
}
#write li > figure:last-child { margin-bottom: 0.5rem; }
#write ol, #write ul { position: relative; }
img { max-width: 100%; vertical-align: middle; image-orientation: from-image; }
button, input, select, textarea { color: inherit; font: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
*, ::after, ::before { box-sizing: border-box; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; }
p { line-height: inherit; }
h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 4; }
p { orphans: 4; }
h1 { font-size: 2rem; }
h2 { font-size: 1.8rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.4rem; }
h5 { font-size: 1.2rem; }
h6 { font-size: 1rem; }
.md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; }
a { cursor: pointer; }
sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-radius: 4px; cursor: pointer; }
sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; }
figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; }
figure > table { margin: 0px; }
tr { break-inside: avoid; break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
table.md-table td { min-width: 32px; }
.CodeMirror-gutters { border-right: 0px; background-color: inherit; }
.CodeMirror-linenumber { user-select: none; }
.CodeMirror { text-align: left; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
#write pre { white-space: pre-wrap; }
#write.fences-no-line-wrapping pre { white-space: pre; }
#write pre.ty-contain-cm { white-space: normal; }
.CodeMirror-gutters { margin-right: 4px; }
.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background: inherit; position: relative !important; }
.md-fences-adv-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
#write .md-fences.mock-cm { white-space: pre-wrap; }
.md-fences.md-fences-with-lineno { padding-left: 0px; }
#write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; }
.md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; }
.CodeMirror-line, twitterwidget { break-inside: avoid; }
.footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; }
.footnotes + .footnotes { margin-top: 0px; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background: 0px 0px; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li .mathjax-block, li p { margin: 0.5rem 0px; }
li blockquote { margin: 1rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child, li > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; }
#write .footnote-line { white-space: pre-wrap; }
@media print {
  body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; font-variant-ligatures: no-common-ligatures; }
  #write { margin-top: 0px; padding-top: 0px; border-color: transparent !important; }
  .typora-export * { -webkit-print-color-adjust: exact; }
  .typora-export #write { break-after: avoid; }
  .typora-export #write::after { height: 0px; }
  .is-mac table { break-inside: avoid; }
  .typora-export-show-outline .typora-export-sidebar { display: none; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }
p > .md-image:only-child:not(.md-img-error) img, p > img:only-child { display: block; margin: auto; }
#write.first-line-indent p > .md-image:only-child:not(.md-img-error) img { left: -2em; position: relative; }
p > .md-image:only-child { display: inline-block; width: 100%; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.md-math-block { width: 100%; }
.md-math-block:not(:empty)::after { display: none; }
.MathJax_ref { fill: currentcolor; }
[contenteditable="true"]:active, [contenteditable="true"]:focus, [contenteditable="false"]:active, [contenteditable="false"]:focus { outline: 0px; box-shadow: none; }
.md-task-list-item { position: relative; list-style-type: none; }
.task-list-item.md-task-list-item { padding-left: 0px; }
.md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); border: none; }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc-content::after, .md-toc::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); }
.md-toc-item a { text-decoration: none; }
.md-toc-inner:hover { text-decoration: underline; }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
@media screen and (max-width: 48em) {
  .md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
  .md-toc-h4 .md-toc-inner { margin-left: 5em; }
  .md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
  .md-toc-h6 .md-toc-inner { margin-left: 8em; }
}
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: "."; }
code, pre, samp, tt { font-family: var(--monospace); }
kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; }
.md-comment { color: rgb(162, 127, 3); opacity: 0.6; font-family: var(--monospace); }
code { text-align: left; vertical-align: initial; }
a.md-print-anchor { white-space: pre !important; border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; background: 0px 0px !important; text-decoration: initial !important; text-shadow: initial !important; }
.os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; }
.md-diagram-panel > svg { max-width: 100%; }
[lang="flow"] svg, [lang="mermaid"] svg { max-width: 100%; height: auto; }
[lang="mermaid"] .node text { font-size: 1rem; }
table tr th { border-bottom: 0px; }
video { max-width: 100%; display: block; margin: 0px auto; }
iframe { max-width: 100%; width: 100%; border: none; }
.highlight td, .highlight tr { border: 0px; }
mark { background: rgb(255, 255, 0); color: rgb(0, 0, 0); }
.md-html-inline .md-plain, .md-html-inline strong, mark .md-inline-math, mark strong { color: inherit; }
.md-expand mark .md-meta { opacity: 0.3 !important; }
mark .md-meta { color: rgb(0, 0, 0); }
@media print {
  .typora-export h1, .typora-export h2, .typora-export h3, .typora-export h4, .typora-export h5, .typora-export h6 { break-inside: avoid; }
}
.md-diagram-panel .messageText { stroke: none !important; }
.md-diagram-panel .start-state { fill: var(--node-fill); }
.md-diagram-panel .edgeLabel rect { opacity: 1 !important; }
.md-fences.md-fences-math { font-size: 1em; }
.md-fences-advanced:not(.md-focus) { padding: 0px; white-space: nowrap; border: 0px; }
.md-fences-advanced:not(.md-focus) { background: inherit; }
.typora-export-show-outline .typora-export-content { max-width: 1440px; margin: auto; display: flex; flex-direction: row; }
.typora-export-sidebar { width: 300px; font-size: 0.8rem; margin-top: 80px; margin-right: 18px; }
.typora-export-show-outline #write { --webkit-flex:2; flex: 2 1 0%; }
.typora-export-sidebar .outline-content { position: fixed; top: 0px; max-height: 100%; overflow: hidden auto; padding-bottom: 30px; padding-top: 60px; width: 300px; }
@media screen and (max-width: 1024px) {
  .typora-export-sidebar, .typora-export-sidebar .outline-content { width: 240px; }
}
@media screen and (max-width: 800px) {
  .typora-export-sidebar { display: none; }
}
.outline-content li, .outline-content ul { margin-left: 0px; margin-right: 0px; padding-left: 0px; padding-right: 0px; list-style: none; }
.outline-content ul { margin-top: 0px; margin-bottom: 0px; }
.outline-content strong { font-weight: 400; }
.outline-expander { width: 1rem; height: 1.42857rem; position: relative; display: table-cell; vertical-align: middle; cursor: pointer; padding-left: 4px; }
.outline-expander::before { content: ""; position: relative; font-family: Ionicons; display: inline-block; font-size: 8px; vertical-align: middle; }
.outline-item { padding-top: 3px; padding-bottom: 3px; cursor: pointer; }
.outline-expander:hover::before { content: ""; }
.outline-h1 > .outline-item { padding-left: 0px; }
.outline-h2 > .outline-item { padding-left: 1em; }
.outline-h3 > .outline-item { padding-left: 2em; }
.outline-h4 > .outline-item { padding-left: 3em; }
.outline-h5 > .outline-item { padding-left: 4em; }
.outline-h6 > .outline-item { padding-left: 5em; }
.outline-label { cursor: pointer; display: table-cell; vertical-align: middle; text-decoration: none; color: inherit; }
.outline-label:hover { text-decoration: underline; }
.outline-item:hover { border-color: rgb(245, 245, 245); background-color: var(--item-hover-bg-color); }
.outline-item:hover { margin-left: -28px; margin-right: -28px; border-left: 28px solid transparent; border-right: 28px solid transparent; }
.outline-item-single .outline-expander::before, .outline-item-single .outline-expander:hover::before { display: none; }
.outline-item-open > .outline-item > .outline-expander::before { content: ""; }
.outline-children { display: none; }
.info-panel-tab-wrapper { display: none; }
.outline-item-open > .outline-children { display: block; }
.typora-export .outline-item { padding-top: 1px; padding-bottom: 1px; }
.typora-export .outline-item:hover { margin-right: -8px; border-right: 8px solid transparent; }
.typora-export .outline-expander::before { content: "+"; font-family: inherit; top: -1px; }
.typora-export .outline-expander:hover::before, .typora-export .outline-item-open > .outline-item > .outline-expander::before { content: "−"; }
.typora-export-collapse-outline .outline-children { display: none; }
.typora-export-collapse-outline .outline-item-open > .outline-children, .typora-export-no-collapse-outline .outline-children { display: block; }
.typora-export-no-collapse-outline .outline-expander::before { content: "" !important; }
.typora-export-show-outline .outline-item-active > .outline-item .outline-label { font-weight: 700; }
.md-inline-math-container mjx-container { zoom: 0.95; }


.CodeMirror { height: auto; }
.CodeMirror.cm-s-inner { background: inherit; }
.CodeMirror-scroll { overflow: auto hidden; z-index: 3; }
.CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler { background-color: rgb(255, 255, 255); }
.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background: inherit; white-space: nowrap; }
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
.cm-s-inner .cm-variable { color: rgb(0, 0, 0); }
.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
.cm-s-inner .cm-property { color: rgb(0, 0, 0); }
.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }
.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: rgb(0, 0, 255); }
.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
.cm-negative { color: rgb(221, 68, 68); }
.cm-positive { color: rgb(34, 153, 34); }
.cm-header, .cm-strong { font-weight: 700; }
.cm-del { text-decoration: line-through; }
.cm-em { font-style: italic; }
.cm-link { text-decoration: underline; }
.cm-error { color: red; }
.cm-invalidchar { color: red; }
.cm-constant { color: rgb(38, 139, 210); }
.cm-defined { color: rgb(181, 137, 0); }
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
.cm-s-inner .CodeMirror-activeline-background { background: inherit; }
.CodeMirror { position: relative; overflow: hidden; }
.CodeMirror-scroll { height: 100%; outline: 0px; position: relative; box-sizing: content-box; background: inherit; }
.CodeMirror-sizer { position: relative; }
.CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar { position: absolute; z-index: 6; display: none; outline: 0px; }
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow: hidden; }
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow: auto hidden; }
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 10px; z-index: 3; overflow-y: hidden; }
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: 0px 0px !important; border: none !important; }
.CodeMirror-gutter-background { position: absolute; top: 0px; bottom: 0px; z-index: 4; }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
.CodeMirror-lines { cursor: text; }
.CodeMirror pre { border-radius: 0px; border-width: 0px; background: 0px 0px; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; overflow-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; }
.CodeMirror-wrap pre { overflow-wrap: break-word; white-space: pre-wrap; word-break: normal; }
.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; }
.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; }
.CodeMirror-linebackground { position: absolute; inset: 0px; z-index: 0; }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0px; }
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
.cm-searching { background: rgba(255, 255, 0, 0.4); }
span.cm-underlined { text-decoration: underline; }
span.cm-strikethrough { text-decoration: line-through; }
.cm-tw-syntaxerror { color: rgb(255, 255, 255); background-color: rgb(153, 0, 0); }
.cm-tw-deleted { text-decoration: line-through; }
.cm-tw-header5 { font-weight: 700; }
.cm-tw-listitem:first-child { padding-left: 10px; }
.cm-tw-box { border-style: solid; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-color: inherit; border-top-width: 0px !important; }
.cm-tw-underline { text-decoration: underline; }
@media print {
  .CodeMirror div.CodeMirror-cursor { visibility: hidden; }
}


/* cyrillic-ext */
/* cyrillic */
/* greek-ext */
/* greek */
/* vietnamese */
/* latin-ext */
/* latin */
/* cyrillic-ext */
/* cyrillic */
/* greek-ext */
/* greek */
/* vietnamese */
/* latin-ext */
/* latin */
/* cyrillic-ext */
/* cyrillic */
/* greek-ext */
/* greek */
/* vietnamese */
/* latin-ext */
/* latin */
/* cyrillic-ext */
/* cyrillic */
/* greek-ext */
/* greek */
/* vietnamese */
/* latin-ext */
/* latin */
@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 600;
    src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('file:///C://Users//Mind//AppData//Roaming//Typora/themes/vue/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdu.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}@import '';

:root {
    --side-bar-bg-color: #fff;
    --control-text-color: #777;
    --font-sans-serif: 'Ubuntu', 'Source Sans Pro', sans-serif !important;
    --font-monospace: 'Fira Code', 'Roboto Mono', monospace !important;
}

html {
    font-size: 16px;
}

body {
    font-family: var(--font-sans-serif);
    color: #34495e;
    -webkit-font-smoothing: antialiased;
    line-height: 1.6rem;
    letter-spacing: 0;
    margin: 0;
    overflow-x: hidden;
}

#write {
    max-width: 860px;
    margin: 0 auto;
    padding: 20px 30px 100px;
}

#write p {
    line-height: 1.6rem;
    word-spacing: .05rem;
}

#write ol li {
    padding-left: 0.5rem;
}

#write > ul:first-child,
#write > ol:first-child {
    margin-top: 30px;
}

body > *:first-child {
    margin-top: 0 !important;
}

body > *:last-child {
    margin-bottom: 0 !important;
}

a {
    color: #42b983;
    font-weight: 600;
    padding: 0 2px;
    text-decoration: none;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    position: relative;
    margin-top: 1rem;
    margin-bottom: 1rem;
    font-weight: bold;
    line-height: 1.4;
    cursor: text;
}

h1:hover a.anchor,
h2:hover a.anchor,
h3:hover a.anchor,
h4:hover a.anchor,
h5:hover a.anchor,
h6:hover a.anchor {
    text-decoration: none;
}

h1 tt,
h1 code {
    font-size: inherit !important;
}

h2 tt,
h2 code {
    font-size: inherit !important;
}

h3 tt,
h3 code {
    font-size: inherit !important;
}

h4 tt,
h4 code {
    font-size: inherit !important;
}

h5 tt,
h5 code {
    font-size: inherit !important;
}

h6 tt,
h6 code {
    font-size: inherit !important;
}

h2 a,
h3 a {
    color: #34495e;
}

h1 {
    padding-bottom: .4rem;
    font-size: 2.2rem;
    line-height: 1.3;
}

h2 {
    font-size: 1.75rem;
    line-height: 1.225;
    margin: 35px 0 15px;
    padding-bottom: 0.5em;
    border-bottom: 1px solid #ddd;
}

h3 {
    font-size: 1.4rem;
    line-height: 1.43;
    margin: 20px 0 7px;
}

h4 {
    font-size: 1.2rem;
}

h5 {
    font-size: 1rem;
}

h6 {
    font-size: 1rem;
    color: #777;
}

p,
blockquote,
ul,
ol,
dl,
table {
    margin: 0.8em 0;
}

li > ol,
li > ul {
    margin: 0 0;
}

hr {
    height: 2px;
    padding: 0;
    margin: 16px 0;
    background-color: #e7e7e7;
    border: 0 none;
    overflow: hidden;
    box-sizing: content-box;
}

body > h2:first-child {
    margin-top: 0;
    padding-top: 0;
}

body > h1:first-child {
    margin-top: 0;
    padding-top: 0;
}

body > h1:first-child + h2 {
    margin-top: 0;
    padding-top: 0;
}

body > h3:first-child,
body > h4:first-child,
body > h5:first-child,
body > h6:first-child {
    margin-top: 0;
    padding-top: 0;
}

a:first-child h1,
a:first-child h2,
a:first-child h3,
a:first-child h4,
a:first-child h5,
a:first-child h6 {
    margin-top: 0;
    padding-top: 0;
}

h1 p,
h2 p,
h3 p,
h4 p,
h5 p,
h6 p {
    margin-top: 0;
}

li p.first {
    display: inline-block;
}

ul,
ol {
    padding-left: 30px;
}

ul:first-child,
ol:first-child {
    margin-top: 0;
}

ul:last-child,
ol:last-child {
    margin-bottom: 0;
}

blockquote {
    border-left: 4px solid #42b983;
    padding: 10px 15px;
    color: #777;
    background-color: rgba(66, 185, 131, .1);
}

table {
    padding: 0;
    word-break: initial;
}

table tr {
    border-top: 1px solid #dfe2e5;
    margin: 0;
    padding: 0;
}

table tr:nth-child(2n),
thead {
    background-color: #fafafa;
}

table tr th {
    font-weight: bold;
    border: 1px solid #dfe2e5;
    border-bottom: 0;
    text-align: left;
    margin: 0;
    padding: 6px 13px;
}

table tr td {
    border: 1px solid #dfe2e5;
    text-align: left;
    margin: 0;
    padding: 6px 13px;
}

table tr th:first-child,
table tr td:first-child {
    margin-top: 0;
}

table tr th:last-child,
table tr td:last-child {
    margin-bottom: 0;
}

#write strong {
    padding: 0 1px;
}

#write em {
    padding: 0 5px 0 2px;
}

#write table thead th {
    background-color: #f2f2f2;
}

#write .CodeMirror-gutters {
    border-right: none;
}

#write .md-fences {
    border: 1px solid #F4F4F4;
    -webkit-font-smoothing: initial;
    margin: 0.8rem 0 !important;
    padding: 0.3rem 0 !important;
    line-height: 1.43rem;
    background-color: #F8F8F8 !important;
    border-radius: 2px;
    font-family: var(--font-monospace);
    font-size: 0.85rem;
    word-wrap: normal;
}

#write .CodeMirror-wrap .CodeMirror-code pre {
    padding-left: 12px;
}

#write code, tt {
    padding: 2px 4px;
    border-radius: 2px;
    font-family: var(--font-monospace);
    font-size: 0.92rem;
    color: #e96900;
    background-color: #f8f8f8;
}

tt {
    margin: 0 2px;
}

#write .md-footnote {
    background-color: #f8f8f8;
    color: #e96900;
}

/* heighlight. */
#write mark {
    background-color: #EBFFEB;
    border-radius: 2px;
    padding: 2px 4px;
    margin: 0 2px;
    color: #222;
    font-weight: 500;
}

#write del {
    padding: 1px 2px;
}

.cm-s-inner .cm-link,
.cm-s-inner.cm-link {
    color: #22a2c9;
}

.cm-s-inner .cm-string {
    color: #22a2c9;
}

.md-task-list-item > input {
    margin-left: -1.3em;
}

@media print {
    html {
        font-size: 13px;
    }

    table,
    pre {
        page-break-inside: avoid;
    }

    pre {
        word-wrap: break-word;
    }
}

.md-fences {
    background-color: #f8f8f8;
}

.md-diagram-panel {
    position: static !important;
}

#write pre.md-meta-block {
    padding: 1rem;
    font-size: 85%;
    line-height: 1.45;
    background-color: #f7f7f7;
    border: 0;
    border-radius: 3px;
    color: #777777;
    margin-top: 0 !important;
}

.mathjax-block > .code-tooltip {
    bottom: .375rem;
}

#write > h3.md-focus:before {
    left: -1.5625rem;
    top: .375rem;
}

#write > h4.md-focus:before {
    left: -1.5625rem;
    top: .285714286rem;
}

#write > h5.md-focus:before {
    left: -1.5625rem;
    top: .285714286rem;
}

#write > h6.md-focus:before {
    left: -1.5625rem;
    top: .285714286rem;
}

.md-image > .md-meta {
    border-radius: 3px;
    font-family: var(--font-monospace);
    padding: 2px 0 0 4px;
    font-size: 0.9em;
    color: inherit;
}

.md-tag {
    color: inherit;
}

.md-toc {
    margin-top: 20px;
    padding-bottom: 20px;
}

.sidebar-tabs {
    border-bottom: none;
}

#typora-quick-open {
    border: 1px solid #ddd;
    background-color: #f8f8f8;
}

#typora-quick-open-item {
    background-color: #FAFAFA;
    border-color: #FEFEFE #e5e5e5 #e5e5e5 #eee;
    border-style: solid;
    border-width: 1px;
}

#md-notification:before {
    top: 10px;
}

/** focus mode */

.on-focus-mode blockquote {
    border-left-color: rgba(85, 85, 85, 0.12);
}

header,
.context-menu,
.megamenu-content,
footer {
    font-family: var(--font-sans-serif);
}

.file-node-content:hover .file-node-icon,
.file-node-content:hover .file-node-open-state {
    visibility: visible;
}

.mac-seamless-mode #typora-sidebar {
    background-color: var(--side-bar-bg-color);
}

.md-lang {
    color: #b4654d;
}

.html-for-mac .context-menu {
    --item-hover-bg-color: #E6F0FE;
}



</style><title>面试题</title>
</head>
<body class='typora-export os-windows'><div class='typora-export-content'>
<div id='write'  class=''><h1 id='questions--answers'><span>Questions &amp; Answers</span></h1><h2 id='java-基础'><span>JAVA 基础</span></h2><h3 id='list--map'><span>List &amp; Map</span></h3><p><strong><code>ArrayList 与 LinkedList的区别</code></strong></p><blockquote><p><span>AL底层结构为数组，LL底层为双向链表</span></p><p><span>AL随机访问速度快，LL插入删除速度优于AL（AL需要移动元素或扩容）</span></p><p><span>LL相比AL占用更多内存 底层存储多个两个引用变量（pre 和 next</span><strong><span>）</span></strong></p></blockquote><p><strong><code>ArrayList初始化和扩容</code></strong></p><blockquote><p><span>若调用空参构造则创建一个空数组长度为0（惰性加载）</span>
<span>在第一次调用add时初始化数组的容量为10</span></p><p><span>若调用有参构造，则按照传入的长度（正整数）创建</span></p><p><span>扩容：</span>
<code>newCapacity = oldCapacity + (oldCapacity &gt;&gt; 1);</code>
<span>扩容长度为原数组大小的1.5倍</span></p></blockquote><p><strong><code>HashMap put的流程</code></strong></p><blockquote><ol start='' ><li><p><span>HashMap 是懒惰加载数组的,首次使用才创建</span></p></li><li><p><span>二次hash计算索引</span></p></li><li><p><span>若下标还没被占用, 创建Node占用返回</span></p></li><li><p><span>若下标已被占用</span></p><ol start='' ><li><span>若是TreeNode 走TreeNode的添加或更新逻辑</span></li><li><span>若是普通Node,走链表的添加或更新逻辑, 若达到树化条件,则执行树化逻辑</span></li></ol></li><li><p><span>返回前查看容量是否超过阈值, 一旦超过执行扩容逻辑</span></p></li></ol></blockquote><p><strong><code>HashMap的加载因子为什么是0.75</code></strong></p><blockquote><p><span>为了在空间上和时间上取得较好的平衡</span></p><p><span>若大于这个值,空间节省了,但链表的长度变长,影响性能.</span></p><p><span>若小于这个值,Hash冲突减少了,但扩容会更加频繁,造成不必要的空间浪费</span></p></blockquote><p><strong><code>HashMap的索引是如何计算的？ 为什么要进行二次hash？ 数组容量为何是2的n次幂？</code></strong></p><blockquote><p><span>索引计算:</span></p><ul><li><span>key的二次hash值 mod capacity</span></li></ul><p><span>为什么要进行二次hash:</span></p><ul><li><span>由于数组容量为2的n次幂单次hash会导致分布不均匀, </span>
<span>二次hash就是为了让元素分布更加均匀</span></li></ul><p><span>数组容量为何是2</span><sup><span>n</span></sup></p><ul><li><span>当数组的容量为2的n次幂时,可对取模运算转换为位运算，效率更高 </span>
<span>原:key mod capacity --&gt; key &amp; (capacity - 1)</span></li></ul></blockquote><p><strong><code>HashMap 的key有什么要求，是否可以为null？</code></strong></p><blockquote><ol start='' ><li><span>必须实现 equals 和 hashCode</span></li><li><span>作为key的内容不可变</span></li></ol><p><span>HashMap的key和value都可以为null, ConcurrentHashMap与之相反</span></p></blockquote><p><strong><code>HashMap何时树化</code></strong></p><blockquote><p><span>树化的条件有两个：</span></p><ol start='' ><li><span>数组的长度大于或等于64</span></li><li><span>若某个链表中的长度超过8</span></li></ol><p><span>若数组长度没有到64，但链表有长度超过8的，则先通过扩容数组重新计算下标。</span></p></blockquote><p><strong><code>HashMap的红黑树何时退化成链表</code></strong></p><blockquote><ol start='' ><li><span>若remove的为树节点时, root.left, root.left.left, root.right 中有一个为null则会退化为链表</span></li><li><span>在HashMap </span><strong><span>扩容时</span></strong><span> 会重新计算Key的下标, 若重新计算下标后, 红黑树的长度 &lt;= 6时则会退化成链表</span></li></ol></blockquote><p><strong><code>HashMap为什么要用红黑树，为何不一开始就树化，树化的阈值为什么是8？</code></strong></p><blockquote><p><span>使用红黑树是为了防止链表过长而导致查询效率大幅下降。</span></p><p><span>一开始不树化是因为:</span></p><ol start='' ><li><span>普通的Node节点要比TreeNode更加节省空间</span></li><li><span>若链表的长度并不是很长，那链表的查询速度未必会比红黑树慢</span></li><li><span>树化是为了防止特殊情况发生，若有人构造同一hash值的key放入map，大幅涌进链表，导致超长链表，从而引起查询效率下降。</span></li></ol><p><span>阈值为8 还是希望尽可能避免树化的可能，若阈值为8 负载因子为0.75 则链表长度超过8的概率大约为亿分之六</span></p></blockquote><p><strong><code>谈谈ConcurrentHashMap</code></strong></p><blockquote><p><span>初始化方面:</span></p><ul><li><span>默认初始容量16,影响因子0.75; 当数组元素个数</span><strong><span>到达</span></strong><span>3/4时扩容到原来的2倍,并重新计算下标</span></li><li><span>有参构造,指定capacity是并不一定为所指定的capacity大小,</span>
<span>如:若指定capacity=12 则由于12到达了默认容量的3/4 实际的capacity为扩容后的32;</span>
<span>指定的factor也只是在初始化时生效,后续扩容仍旧是以0.75为标准.</span></li></ul><p><span>锁的实现:</span></p><ul><li><span>根据数组的下标(链表的头)来进行加锁, 不同线程访问不同的下标互不影响,反之会被阻塞</span></li></ul><p><span>扩容流程:</span></p><ul><li><span>当达到扩容阈值,从数组的最后一个下标开始将元素移动到新数组中去, 每完成一个下标, 该下标所对应的链表头会置为一个ForwardingNode来标识该下标已完成置换.</span></li></ul><p><span>多线程下的get流程:</span></p><ul><li><span>get不需要加锁</span></li><li><span>若在扩容的过程中其他线程需要执行get操作,则会根据链表头来判断,若为ForwardingNode,则去新链表查询,反之直接返回.</span></li></ul><p><span>多线程下的put流程</span></p><ul><li><span>判断key和value 是否含有null,有则抛出异常</span></li><li><span>计算key的hash 定位Node位置,若没有头节点,则创建Node放入数组,若有则抢到锁时放入</span></li><li><span>若在扩容时进行put,若该线程所put的索引位置还没有扩容到,则直接将元素插入到旧链表中,若put的索引位置为ForwardingNode, 则该线程会协助扩容线程执行扩容。</span></li></ul></blockquote><p><strong><code>Hashtable 和 ConcurrentHashMap都是线程安全的，他们之间有什么区别？</code></strong></p><blockquote><p><span>HashTable 是一个很古老的类, 它使用数组+链表的数据结构,每次上锁时锁的是整个table; 因此 HashTable 的并发度很低.</span></p><p><span>ConcurrentHashMap 1.7使用数组+链表+segment的数据结构, 每次上锁锁一个segment,不同线程访问不同的segment不冲突, 并发度更高.</span></p><p><span>ConcurrentHashMap 1.8 使用数组+链表 每次上锁锁链表的表头,若不同节点访问的头节点不同则互不冲突</span></p></blockquote><h3 id='integer--string'><span>Integer &amp; String</span></h3><p><strong><code>Integer的缓存</code></strong></p><blockquote><p><span>JVM 会将 [-128,127] 的int数值缓存，在通过</span><strong><span>非new方式</span></strong><span>创建该区间的Integer对象会从常量池中获取。</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.2px; left: 12px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">Integer</span> <span class="cm-variable">i</span> <span class="cm-operator">=</span> <span class="cm-number">120</span>;<span class="cm-comment">//底层就是valueOf</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">Integer</span> <span class="cm-variable">j</span> <span class="cm-operator">=</span> <span class="cm-variable-3">Integer</span>.<span class="cm-variable">valueOf</span>(<span class="cm-number">120</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">Integer</span> <span class="cm-variable">k</span> <span class="cm-operator">=</span> <span class="cm-variable-3">Integer</span>.<span class="cm-variable">parseInt</span>(<span class="cm-string">"120"</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">Integer</span> <span class="cm-variable">l</span> <span class="cm-operator">=</span> <span class="cm-keyword">new</span> <span class="cm-variable-3">Integer</span>(<span class="cm-number">120</span>);<span class="cm-comment">//堆中</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">i</span> <span class="cm-operator">==</span> <span class="cm-variable">j</span> <span class="cm-operator">==</span> <span class="cm-variable">k</span>;<span class="cm-comment">//true</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">i</span> <span class="cm-operator">==</span> <span class="cm-variable">l</span><span class="cm-comment">//false</span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 134px;"></div><div class="CodeMirror-gutters" style="display: none; height: 134px;"></div></div></div></pre></blockquote><p><strong><code>String s= new String(&quot;a&quot;) + new String(&quot;b&quot;) 创建了几个对象？</code></strong></p><blockquote><p><span>总共六个对象：</span></p><p><span>对象1：StringBuilder</span></p><p><span>对象2，3：常量池中a，b</span></p><p><span>对象4，5：堆中a，b</span></p><p><span>对象6：常量池中 ab</span></p></blockquote><p><strong><code>String的比较</code></strong></p><blockquote><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.2px; left: 12px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">String</span> <span class="cm-variable">str1</span> <span class="cm-operator">=</span> <span class="cm-string">"a"</span>;</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">String</span> <span class="cm-variable">str2</span> <span class="cm-operator">=</span> <span class="cm-string">"b"</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">String</span> <span class="cm-variable">str3</span> <span class="cm-operator">=</span> <span class="cm-string">"ab"</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">String</span> <span class="cm-variable">str4</span> <span class="cm-operator">=</span> <span class="cm-variable">str1</span> <span class="cm-operator">+</span> <span class="cm-variable">str2</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">String</span> <span class="cm-variable">str5</span> <span class="cm-operator">=</span> <span class="cm-string">"a"</span> <span class="cm-operator">+</span> <span class="cm-string">"b"</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">str3</span> <span class="cm-operator">==</span> <span class="cm-variable">str4</span>);<span class="cm-comment">//false</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">str3</span> <span class="cm-operator">==</span> <span class="cm-variable">str5</span>);<span class="cm-comment">//true</span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 157px;"></div><div class="CodeMirror-gutters" style="display: none; height: 157px;"></div></div></div></pre></blockquote><p><strong><code>String的intern方法做了什么</code></strong></p><blockquote><p><span>当调用str.intern()方法后，JVM 会在当前类的常量池中查找是否存在与str等值的String，</span>
<span>若存在则直接返回常量池中相应Strnig的引用；</span></p><p><span>若不存在，则会在常量池中创建一个等值的String，然后返回这个String在常量池中的引用，自身引用不会变。</span></p><p><span>因此，只要是等值的String对象，使用intern()方法返回的都是常量池中同一个String引用，所以，这些等值的String对象通过intern()后使用==是可以匹配的。</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.2px; left: 12px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; <span class="cm-variable-3">String</span> <span class="cm-variable">s1</span> <span class="cm-operator">=</span> <span class="cm-keyword">new</span> <span class="cm-variable-3">String</span>(<span class="cm-string">"abc"</span>);</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; <span class="cm-variable-3">String</span> <span class="cm-variable">s2</span> <span class="cm-operator">=</span> <span class="cm-string">"abc"</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; <span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">s1</span> <span class="cm-operator">==</span> <span class="cm-variable">s2</span>);<span class="cm-comment">//false</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; <span class="cm-variable-3">String</span> <span class="cm-variable">s3</span> <span class="cm-operator">=</span> <span class="cm-variable">s1</span>.<span class="cm-variable">intern</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; <span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">s1</span> <span class="cm-operator">==</span> <span class="cm-variable">s2</span>);<span class="cm-comment">//false</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; <span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">s3</span> <span class="cm-operator">==</span> <span class="cm-variable">s2</span>);<span class="cm-comment">//true</span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 134px;"></div><div class="CodeMirror-gutters" style="display: none; height: 134px;"></div></div></div></pre></blockquote><h4 id='抽象类和接口的区别'><strong><code>抽象类和接口的区别</code></strong></h4><blockquote><p><span>设计层面的区别:</span></p><p><span>抽象类是对一种</span><strong><span>事物的抽象</span></strong><span>，即对类抽象，而接口是对</span><strong><span>行为的抽象</span></strong><span>。</span>
<span>抽象类是对整个类整体进行抽象，包括属性、行为，但是接口却是对类局部（行为）进行抽象</span></p><p><span>语法层面的区别:</span></p><ul><li><span>1)抽象类可以提供成员方法的实现细节，而接口中只能存在public abstract 方法；</span></li><li><span>2）抽象类中的成员变量可以是各种类型的，而接口中的成员变量只能是public static final类型的；</span></li><li><span>3）接口中不能含有静态代码块以及静态方法，而抽象类可以有静态代码块和静态方法；</span></li><li><span>4）一个类只能继承一个抽象类，而一个类却可以实现多个接口。</span></li></ul></blockquote><h4 id='error-和-exception-有什么区别'><strong><code>Error 和 Exception 有什么区别？</code></strong></h4><blockquote><p><span>(1)Error类和Exception类都是继承Throwable类</span></p><p><span>(2)Error（错误）是系统中的错误，程序员是不能改变的和处理的，是在程序编译时出现的错误，只能通过修改程序才能修正。</span>
<span>	</span><span>一般是指与虚拟机相关的问题，如系统崩溃，虚拟机错误，内存空间不足，方法调用栈溢等。</span></p><p><span>(3)Exception（异常）表示程序可以处理的异常，可以捕获且可能恢复。</span>
<span>	</span><span>遇到这类异常，应该尽可能处理异常，使程序恢复运行，而不应该随意终止异常。</span></p><p><span>Exception又分为两类:</span></p><p><span>CheckedException：（编译时异常） 需要用try——catch显示的捕获，对于可恢复的异常使用CheckedException。</span>
<span>UnCheckedException（RuntimeException）：（运行时异常）不需要捕获，对于程序错误（不可恢复）的异常使用RuntimeException。</span></p><p><strong><span>常见的RuntimeException异常:</span></strong>
<span>IllegalArgumentException：此异常表明向方法传递了一个不合法或不正确的参数。</span>
<span>NullpointerException：空指针异常</span>
<span>IndexOutOfBoundsException：索引超出边界异常</span></p><p><strong><span>常见的CheckedException异常:</span></strong>
<span>我们在编写程序过程中try——catch捕获到的异常都是CheckedException。</span>
<span>io包中的IOExecption及其子类，都是CheckedException。</span></p></blockquote><h4 id='try里有一个-return-语句那么紧跟在这个-try-后的-finally里的代码会不会被执行什么时候被执行在-return-前还是后'><strong><code>try{}里有一个 return 语句，那么紧跟在这个 try 后的 finally{}里的代码会不会被执行，什么时候被执行，在 return 前还是后?</code></strong></h4><blockquote><p><span>try 中的 return 语句调用的函数先于 finally 中调用的函数执行，也就是说 return 语句先执行，finally 语句后执行，但 return 并不是让函数马上返回，而是 return 语句执行后，将把返回结果记录，此时函数并不是马上返回，它要执行 finally 语句后,再把记录的值返回！但此时会出现两种情况：</span></p><p><span>①、如果finally中也有return，则会直接返回并终止程序，函数栈中的return不会被完成！；</span></p><p><span>②、如果finally中没有return，则在执行完finally中的代码之后，会将函数栈中的try中的return的内容返回并终止程序；</span></p><p><span>catch同try;</span></p></blockquote><p>&nbsp;</p><h2 id='jvm'><span>JVM</span></h2><h4 id='什么是字节码采用字节码的好处是什么'><strong><code>什么是字节码？采用字节码的好处是什么？</code></strong></h4><blockquote><p><span>字节码：Java源代码经过虚拟机编译器编译后产生的文件（即扩展为.class的文件），它不面向任何特定的处理器，只面向</span><strong><span>虚拟机</span></strong><span>。</span></p><p><span>采用字节码的好处：</span>
<span>Java语言通过字节码的方式，在</span><strong><span>一定程度上解决了传统解释型语言执行效率低的问题</span></strong><span>，同时又保留了解释型语言</span><strong><span>可移植</span></strong><span>的特点。所以Java程序运行时比较高效，而且，由于字节码并不专对一种特定的机器，因此，Java程序</span><strong><span>无须重新编译便可在多种不同的计算机上运行。</span></strong></p></blockquote><p>&nbsp;</p><h2 id='mysql'><span>MySQL</span></h2><h4 id='索引什么时候失效'><strong><code>索引什么时候失效</code></strong></h4><blockquote><ol start='' ><li><span>用or时左右两边非全有索引; or两边为 &gt; 和 &lt; 范围查询时，索引失效。</span></li><li><span>复合索引未用左列字段;</span></li><li><span>like以%开头;</span></li><li><span>需要类型转换;</span></li><li><span>where中索引列有运算;</span></li><li><span>where中索引列使用了函数;</span></li><li><span>如果mysql觉得全表扫描更快时（数据少）;</span></li></ol></blockquote><h4 id='什么时候没必要建立索引'><strong><code>什么时候没必要建立索引?</code></strong></h4><blockquote><ol start='' ><li><span>唯一性差;</span></li><li><span>频繁更新的字段不用（更新索引消耗）;</span></li><li><span>where中不用的字段;</span></li><li><span>text，image等类型不应该建立索引，这些列的数据量大（假如text前10个字符唯一，也可以对text前10个字符建立索引）；</span></li></ol></blockquote><h4 id='事务的隔离级别以及所带来的问题'><strong><code>事务的隔离级别以及所带来的问题</code></strong></h4><blockquote><ol start='' ><li><span>读未提交（READ UNCOMMITTED）</span></li><li><span>读已提交 （READ COMMITTED）</span></li><li><span>可重复读 （REPEATABLE READ）</span></li><li><span>串行化 （SERIALIZABLE）</span></li></ol><p><strong><span>脏读 </span></strong><span>(Dirty Read):</span></p><p><span>	</span><span>一个事务读到了另一个未提交事务修改过的数据.</span></p><p><strong><span>不可重复读</span></strong><span>（Non-Repeatable Read）:</span></p><p><span>	</span><span>一个事务只能读到另一个事务已经提交的所修改/删除过的数据.</span></p><p><strong><span>幻读</span></strong><span>（Phantom）:</span></p><p><span>	</span><span>幻读指当用户读取某一范围的数据行时，另一个事务又在该范围内插入了新</span><span>	</span><span>行，当用户再读取该范围的数据行时，会发现有新的“幻影” 行。</span></p><p><strong><span>不同隔离级别可能含有的问题:</span></strong></p><figure><table><thead><tr><th style='text-align:center;' ><span>隔离级别</span></th><th style='text-align:center;' ><span>脏读</span></th><th style='text-align:center;' ><span>不可重复读</span></th><th style='text-align:center;' ><span>幻读</span></th></tr></thead><tbody><tr><td style='text-align:center;' ><span>读未提交</span></td><td style='text-align:center;' ><span>可能</span></td><td style='text-align:center;' ><span>可能</span></td><td style='text-align:center;' ><span>可能</span></td></tr><tr><td style='text-align:center;' ><span>读已提交</span></td><td style='text-align:center;' ><span>不可能</span></td><td style='text-align:center;' ><span>可能</span></td><td style='text-align:center;' ><span>可能</span></td></tr><tr><td style='text-align:center;' ><span>可重复读</span></td><td style='text-align:center;' ><span>不可能</span></td><td style='text-align:center;' ><span>不可能</span></td><td style='text-align:center;' ><span>可能</span></td></tr><tr><td style='text-align:center;' ><span>串行化</span></td><td style='text-align:center;' ><span>不可能</span></td><td style='text-align:center;' ><span>不可能</span></td><td style='text-align:center;' ><span>不可能</span></td></tr></tbody></table></figure></blockquote><h4 id='myism-和-innodb的区别'><strong><code>MyISM 和 InnoDB的区别</code></strong></h4><blockquote><ol start='' ><li><span>InnoDB支持事务,MyISM不支持</span></li><li><span>InnoDB支持外键</span></li><li><span>InnoDB不保存具体的行数,执行</span><code>count(*)</code><span>或</span><code>select * from xxx</code><span>需要全表扫描.MyISM使用一个变量保存了整个表的行数</span></li><li><span>InnoDB支持行锁和表锁,MyISM只支持表锁,因此InnoDB的并发度更好</span></li><li><span>InnoDB必须有唯一索引(如主键),用户没有指定会自动生成一个Row_id来充当默认主键. MyISM可以没有</span></li></ol></blockquote><h4 id='什么是最左前缀原则什么是最左匹配原则'><strong><code>什么是最左前缀原则？什么是最左匹配原则</code></strong></h4><blockquote><p><strong><span>最左前缀原则：顾名思义是最左优先，以最左边的为起点任何连续的索引都能匹配上。</span></strong></p><p><span>（1）如果第一个字段是范围查询需要单独建一个索引；</span></p><p><span>（2）在创建多列索引时，要根据业务需求，where子句中使用最频繁的一列放在最左边；</span></p><p><strong><span>当创建(a,b,c)复合索引时，想要索引生效的话，只能使用 a和ab、ac和abc三种组合.</span></strong></p><p><span>实例：以下是常见的几个查询：</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="mysql"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="mysql"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.2px; left: 12px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">mysql<span class="cm-operator">&gt;</span><span class="cm-keyword">SELECT</span> <span class="cm-variable-2">`a`</span><span class="cm-punctuation">,</span><span class="cm-variable-2">`b`</span><span class="cm-punctuation">,</span><span class="cm-variable-2">`c`</span> <span class="cm-keyword">FROM</span> A <span class="cm-keyword">WHERE</span> <span class="cm-variable-2">`a`</span><span class="cm-operator">=</span><span class="cm-string">'a1'</span> <span class="cm-punctuation">;</span> //索引生效</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">mysql<span class="cm-operator">&gt;</span><span class="cm-keyword">SELECT</span> <span class="cm-variable-2">`a`</span><span class="cm-punctuation">,</span><span class="cm-variable-2">`b`</span><span class="cm-punctuation">,</span><span class="cm-variable-2">`c`</span> <span class="cm-keyword">FROM</span> A <span class="cm-keyword">WHERE</span> <span class="cm-variable-2">`b`</span><span class="cm-operator">=</span><span class="cm-string">'b2'</span> <span class="cm-keyword">AND</span> <span class="cm-variable-2">`c`</span><span class="cm-operator">=</span><span class="cm-string">'c2'</span><span class="cm-punctuation">;</span> //索引失效</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">mysql<span class="cm-operator">&gt;</span><span class="cm-keyword">SELECT</span> <span class="cm-variable-2">`a`</span><span class="cm-punctuation">,</span><span class="cm-variable-2">`b`</span><span class="cm-punctuation">,</span><span class="cm-variable-2">`c`</span> <span class="cm-keyword">FROM</span> A <span class="cm-keyword">WHERE</span> <span class="cm-variable-2">`a`</span><span class="cm-operator">=</span><span class="cm-string">'a3'</span> <span class="cm-keyword">AND</span> <span class="cm-variable-2">`c`</span><span class="cm-operator">=</span><span class="cm-string">'c3'</span><span class="cm-punctuation">;</span> //索引生效，实际上值使用了索引a</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 90px;"></div><div class="CodeMirror-gutters" style="display: none; height: 90px;"></div></div></div></pre></blockquote><h4 id='count-和-count1和count列名区别'><strong><code>count(*) 和 count(1)和count(列名)区别</code></strong></h4><blockquote><ul><li><p><span>count(*)包括了所有的列，相当于行数，在统计结果的时候，不会忽略NULL值</span></p></li><li><p><span>count(1)与count(*)一致,没有性能差异,但更建议使用count( * )</span></p><p><code>InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.</code></p></li><li><p><span>count(列名)不会统计该列值为null的行</span></p></li></ul></blockquote><h4 id='索引底层数据结构'><code>索引底层数据结构</code></h4><blockquote><p><strong><span>MySQL 中的索引使用 B+ Tree 数据结构。</span></strong></p><p><span>B+ Tree 是一种平衡树，每个节点都包含一个关键字序列(某一列的值)，以及一些指向子节点的指针。与普通的 B Tree 不同的是，所有的数据都存储在</span><strong><span>叶子节点</span></strong><span>上，这使得查询操作更加高效。</span></p><p><span>在 MySQL 中，</span><strong><span>每个索引都是一个 B+ Tree</span></strong><span>，它的根节点指向所有的叶子节点。在叶子节点上，每一行数据都是由一个关键字（索引列的值）和一个指向数据记录的指针组成的。在查询数据时，MySQL 会通过 B+ Tree 来快速查询到符合条件的数据，进而获取数据记录。</span></p><p><span>B+ Tree 是一种高效的数据结构，特别适用于大量数据的存储和查询。它具有很高的查询性能，并且能够快速平衡数据，从而维护数据的有序性。因此，B+ Tree 是一种非常适合存储索引的数据结构。</span></p></blockquote><h4 id='聚集索引和非聚集索引'><code>聚集索引和非聚集索引</code></h4><blockquote><p><span>聚集索引是指把数据表中的行存储在索引键的顺序中，通常以主键作为索引，这样可以快速查询排序后的数据。聚集索引可以加快需要访问排序数据的查询，因为它可以直接在索引中找到数据。</span></p><p><span>非聚集索引是指与数据表中的每一行对应的索引，其中索引中包含索引键和指向数据表中对应行的指针。非聚集索引用于加速查询，特别是对非唯一的索引键的查询，因为它可以直接指向数据表中的数据，而不需要扫描整个表。</span></p></blockquote><h4 id='什么是回表什么是索引覆盖'><code>什么是回表，什么是索引覆盖？</code></h4><blockquote><p><span>若查询的语句是通过先查询非聚簇索引获取主键，再通过主键从聚集索引中查取数据的过程，称为回表。</span></p><p><span>若查询使用了索引，并且需要返回的列，在该索引中已经全部能够找到, 这时就不再需要</span><strong><code>回表</code></strong><span>查询其他数据, 加快了查询速度。</span></p></blockquote><h4 id='sql语句的执行顺序'><code>SQL语句的执行顺序</code></h4><blockquote><ol start='' ><li><span>FROM 子句：从一个或多个表中选择数据。</span></li><li><span>JOIN 子句：如果存在多个表，将它们按照 ON 条件进行关联。</span></li><li><span>WHERE 子句：筛选符合条件的数据。</span></li><li><span>GROUP BY 子句：将数据分组。</span></li><li><span>HAVING 子句：对分组后的数据进行筛选。</span></li><li><span>SELECT 子句：从数据中选择所需的列。</span></li><li><span>DISTINCT 子句：如果选择了 DISTINCT 关键字，则去除重复数据。</span></li><li><span>ORDER BY 子句：对结果进行排序。</span></li><li><span>LIMIT 子句：如果指定了 LIMIT，则选择前 N 条数据。</span></li></ol><p><span> MySQL 会根据查询的复杂程度自动优化查询顺序。在一些情况下，MySQL 可能会对查询进行预处理或重新排列顺序，以提高查询性能。</span></p><p><span>例如，如果查询中包含索引字段，MySQL 可能会将 WHERE 子句放在 FROM 子句前面执行，以便更快地筛选数据。同样，如果使用了聚合函数（例如 COUNT，SUM 等），MySQL 可能会将 GROUP BY 子句放在 WHERE 子句之前执行，以减少不必要的数据处理。</span></p></blockquote><h4 id='事务四大特性'><code>事务四大特性</code></h4><blockquote><ol start='' ><li><p><span>原子性（Atomicity）</span></p><p><span>原子性是指事务包含的所有操作要么全部成功，要么全部失败回滚。因此事务的操作如果成功就必须要完全应用到数据库，如果操作失败则不能对数据库有任何影响。</span></p></li><li><p><span>一致性（Consistency）</span></p><p><span>一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态，也就是说一个事务执行之前和执行之后都必须处于一致性状态。</span></p><p><span>拿转账来说，假设用户A和用户B两者的钱加起来一共是5000，那么不管A和B之间如何转账，转几次账，事务结束后两个用户的钱相加起来应该还得是5000，这就是事务的一致性。</span></p></li><li><p><span>隔离性（Isolation）</span></p><p><span>隔离性是当多个用户并发访问数据库时，比如操作同一张表时，数据库为每一个用户开启的事务，不能被其他事务的操作所干扰，多个并发事务之间要相互隔离。</span></p></li><li><p><span>持久性（Durability）</span></p><p><span>持久性是指一个事务一旦被提交了，那么对数据库中的数据的改变就是永久性的，即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。</span></p></li></ol></blockquote><p>&nbsp;</p><h2 id='spring'><span>Spring</span></h2><h4 id='什么是ioc'><strong><code>什么是IOC</code></strong></h4><blockquote><p><strong><span>控制反转（IOC  Inversion of Control ）</span></strong><span>传统的 java 开发模式中，当需要一个对象时，我们会自己 使用 new 或者 getInstance 等直接或者间接调用构造方法创建一个对象。而在 spring 开发模式中，spring 容器使用了工厂模式为我们创建了所需要的对象， 不需要我们自己创建了，直接调用 spring 提供的对象就可以了，这是控制反转的思想</span></p></blockquote><h4 id='什么是di'><strong><code>什么是DI</code></strong></h4><blockquote><p><strong><span>依赖注入(Dependency Injection)</span></strong>
<strong><span>由容器动态的将某个依赖关系注入到组件之中</span></strong><span>。</span><strong><span>依赖注入的目的并非为软件系统带来更多功能，而是为了提升组件重用的频率，并为系统搭建一个灵活、可扩展的平台。</span></strong><span>通过</span><a href='https://so.csdn.net/so/search?q=依赖注入&amp;spm=1001.2101.3001.7020'><span>依赖注入</span></a><span>机制，我们只需要通过简单的配置，而无需任何代码就可指定目标需要的资源，完成自身的业务逻辑，而不需要关心具体的资源来自何处，由谁实现。</span></p></blockquote><h4 id='什么是aop'><strong><code>什么是AOP</code></strong></h4><blockquote><p><strong><span>Aspect Oriented Programming</span></strong>
<span>在面向对象编程（oop）思想中，我们将事物纵向抽成 一个个的对象。而在</span><strong><span>面向切面编程</span></strong><span>中，我们将一个个的对象某些类似的方面横向抽成一个切面，对这个切面进行一些如权限控制、事务管理，记录日志等。 公用操作处理的过程就是面向切面编程的思想。</span>
<strong><span>一句话总结：在不改变原有代码的条件下，对该有功能进行扩展；</span></strong></p></blockquote><h4 id='beanfactory和applicationcontext有什么区别'><strong><code>BeanFactory和ApplicationContext有什么区别？</code></strong></h4><blockquote><ul><li><code>BeanFactory</code><span> 是最基本的 Bean 容器，主要提供了创建和管理 Bean 的功能。</span></li><li><code>ApplicationContext</code><span> 在 </span><code>BeanFactory</code><span> 的基础上扩展了更多的功能，例如国际化、事件传递等。</span></li><li><code>BeanFactory</code><span> 的性能比 </span><code>ApplicationContext</code><span> 要低，因为它需要在请求 Bean 时才加载，而 </span><code>ApplicationContext</code><span> 在初始化时就加载所有的 Bean。</span></li></ul></blockquote><h4 id='spring-bean的生命周期'><strong><code>Spring Bean的生命周期</code></strong></h4><blockquote><ol start='' ><li><span>实例化：使用构造器或工厂方法实例化Bean。</span></li><li><span>属性设置：使用setter方法为Bean设置属性。</span></li><li><span>实例化前回调：在Bean实例化之前调用定义的回调方法。</span></li><li><span>实例化后回调：在Bean实例化之后调用定义的回调方法。</span></li><li><span>Bean使用：使用Bean。</span></li><li><span>Bean销毁：销毁Bean之前调用定义的销毁方法。</span></li></ol></blockquote><h4 id='spring事务失效场景'><strong><code>Spring事务失效场景</code></strong></h4><blockquote><ol start='' ><li><span>数据库引擎不支持事务(MyISM)</span></li><li><span>自身调用</span></li><li><span>方法非public</span></li><li><span>事务传播性设置不正确</span></li><li><span>该类没有被Spring管理</span></li><li><span>数据源没有配置事务管理器</span></li><li><span>手动解决异常不抛出</span></li><li><span>异常类型错误(默认为RuntimeException,若抛出Exception 不回滚)</span></li></ol></blockquote><h4 id='spring事务传播机制'><strong><code>Spring事务传播机制</code></strong></h4><blockquote><p><span>Spring事务传播机制是指在多个方法中如何传播事务的机制。Spring支持以下事务传播行为：</span></p><ol start='' ><li><p><span>REQUIRED：如果当前存在事务，则加入该事务；如果当前没有事务，则创建一个新事务。</span></p></li><li><p><span>SUPPORTS：如果当前存在事务，则加入该事务；如果当前没有事务，则以非事务方式执行。</span></p></li><li><p><span>MANDATORY：如果当前存在事务，则加入该事务；如果当前没有事务，则抛出异常。</span></p></li><li><p><span>REQUIRES_NEW：创建一个新事务，如果当前存在事务，则</span><strong><span>挂起该事务</span></strong><span>。</span></p><p><code>“挂起事务”是指暂时将当前事务暂停，当前事务的回滚点以前的操作会被暂时保留，等待当前事务的结束之后再恢复该事务。当前事务的结束指的是当前事务的提交或回滚。</code></p></li><li><p><span>NOT_SUPPORTED：以非事务方式执行操作，如果当前存在事务，则挂起该事务。</span></p></li><li><p><span>NEVER：以非事务方式执行，如果当前存在事务，则抛出异常。</span></p></li><li><p><span>NESTED：如果当前存在事务，则创建一个事务作为当前事务的嵌套事务来执行；如果当前没有事务，则该取值等价于REQUIRED。</span></p></li></ol></blockquote><h4 id='springmvc-工作流程'><strong><code>SpringMVC 工作流程</code></strong></h4><blockquote><ol start='' ><li><span>客户端发送一个请求到服务器。</span></li><li><span>DispatcherServlet（前端控制器）接收到请求，并将请求转发到相应的处理器。</span></li><li><span>处理器映射器（HandlerMapping）根据请求的 URL 匹配相应的处理器（Controller）。</span></li><li><span>匹配的处理器执行相关的业务逻辑。</span></li><li><span>处理器通过模型对象（Model）向视图对象（View）传递数据。</span></li><li><span>视图解析器（ViewResolver）根据视图名称选择相应的视图技术（JSP、FreeMarker、Thymeleaf 等）。</span></li><li><span>视图将数据呈现给客户端。</span></li><li><span>客户端显示结果。</span></li></ol></blockquote><h4 id='springboot自动注入机制'><strong><code>SpringBoot自动注入机制</code></strong></h4><blockquote><p><span>启动类注解</span><code>@SpringBootApplication</code><span>中含有三个主要注解:</span><code>@Configuration</code><span>(允许在上下文中注册额外的 bean 或导入其他配置类)</span><code>@ComponentScan</code><span>(扫描启动类所在的包下所有的类)和</span>
<code>@EnableAutoConfiguration</code><span>(启用 SpringBoot 的自动配置机制)，其中</span>
<code>@EnableAutoConfiguration</code><span>的注解有这个</span><code>@lmport(AutoConfigurationlmportSelector.class))</code><span>;其</span><code>AutoConfigurationlmportSelector</code><span>实现了 </span><code>lmportSelector</code><span>接口中的selectlmports()方法;该方法主要用于获取所有符合条件的类的全限定类名，会再SpringBoot启动的时候把</span><strong><span>spring.factories</span></strong><span>(文件都是配置类全路径名称)这些配置类加载到IOC容器</span></p></blockquote><h4 id='cglib和jdk动态代理的区别'><strong><code>Cglib和JDk动态代理的区别</code></strong></h4><blockquote><p><span>Cglib 和 JDK 动态代理是两种不同的 Java 动态代理实现方式。</span></p><ol start='' ><li><p><span>JDK 动态代理：JDK 动态代理是通过 java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类实现的。它仅支持对接口进行代理，不支持对类进行代理。</span></p></li><li><p><span>Cglib 动态代理：Cglib 动态代理是通过使用字节码技术生成一个子类实现代理，因此它不仅可以代理接口，还可以代理类。</span></p></li><li><p><span>性能：由于 Cglib 生成的是子类，因此性能比 JDK 动态代理要好.</span></p><p><code>Cglib 生成的代理对象是目标类的子类，因此它们可以直接访问目标类的方法，而不必经过反射机制。这就使得 Cglib 生成的代理比 JDK 动态代理要快。</code></p></li><li><p><span>实现难度：由于 JDK 动态代理只支持对接口进行代理，并且实现简单，因此实现难度较低；而 Cglib 生成的是子类，实现难度较高。</span></p></li><li><p><span>适用场景：如果需要对类进行代理，则需要使用 Cglib 动态代理；如果只需要对接口进行代理，则可以使用 JDK 动态代理。</span></p></li></ol></blockquote><p>&nbsp;</p><h2 id='mybatis'><span>MyBatis</span></h2><h4 id='-与--的区别'><strong><code>#{} 与 ${} 的区别</code></strong></h4><blockquote><ol start='' ><li><span>#</span><span>{}表示预处理语句（Prepared Statement），会将变量通过占位符 ? 替换到SQL语句中，并对数据进行类型转换和转义处理，可以防止SQL注入攻击。</span></li><li><span>${}表示字符串替换，直接将变量替换到SQL语句中，不进行类型转换和转义处理，存在SQL注入的风险。</span></li></ol><p><span>因此，在MyBatis中建议使用#{}作为变量占位符。</span></p></blockquote><h4 id='mybatis有哪些事务管理方式'><strong><code>MyBatis有哪些事务管理方式？</code></strong></h4><blockquote><ol start='' ><li><span>基于JDBC的事务管理：使用JDBC API管理事务，这是MyBatis的默认事务管理方式。</span></li><li><span>基于第三方管理的事务管理：使用第三方的事务管理器（如Spring的事务管理器）管理事务，这种方式通常用于在一个更大的环境中管理事务。</span></li></ol><p><span>如果需要在MyBatis中使用事务，通常需要在MyBatis配置文件中进行相关配置，或者在使用第三方管理的事务管理时需要在第三方管理器中进行相关配置。</span></p></blockquote><h4 id='mybatis如何实现动态sql'><strong><code>MyBatis如何实现动态SQL？</code></strong></h4><blockquote><p><span>MyBatis支持动态SQL，使用了特殊的语法来构造SQL语句。</span></p><p><span>有几种不同的语法可以用于实现动态SQL：</span></p><ol start='' ><li><span>if标签：可以通过OGNL表达式(如user.name)来动态决定是否包含某个片段。</span></li><li><span>choose、when、otherwise标签：类似于Java中的switch语句，可以动态决定执行哪个片段。</span></li><li><span>trim标签：可以用于去除没有必要的SQL片段，例如前导空格和后缀的逗号。</span></li><li><span>foreach标签：可以通过循环动态生成SQL语句，例如将一个Java列表转换为一个SQL IN子句。</span></li></ol></blockquote><h4 id='mybatis有哪些缓存机制'><strong><code>MyBatis有哪些缓存机制？</code></strong></h4><blockquote><ol start='' ><li><p><span>一级缓存：MyBatis默认提供的缓存机制，也称作本地缓存。它是每个SqlSession的缓存，并且自动启用。当查询数据时，MyBatis会先查询一级缓存，如果没有找到所需的数据，再去查询数据库。</span></p><p><strong><span>注</span></strong><span>: 若期间有更新或新增操作,缓存会被清除</span></p></li><li><p><span>二级缓存：是可选的缓存机制，可以在多个SqlSession之间共享数据。二级缓存可以通过配置来启用，需要在mapper接口上加注解，并需要缓存实现类。</span></p></li></ol><p><span>在需要的时候，可以通过调用SqlSession的clearCache()方法来手动清除一级缓存，或者通过调用SqlSessionFactory的evictLevel2Cache()方法清除二级缓存。</span></p></blockquote><h4 id='spring是如何控制sqlsession的创建和销毁'><strong><code>Spring是如何控制SqlSession的创建和销毁</code></strong></h4><blockquote><p><span>在Spring中，如果使用了事务管理，则一般可以在一个事务中多次调用Mapper中的方法，这些方法共用一个SqlSession。</span></p><p><span>如果没有使用事务，则每次调用Mapper中的方法都会创建一个新的SqlSession，并在调用完成后销毁。</span></p></blockquote><h2 id='redis'><span>Redis</span></h2><h4 id='rdb-和-aof-机制'><code>RDB 和 AOF 机制</code></h4><blockquote><p><span>Redis提供了两种持久性选项来将数据存储在磁盘上：RDB和AOF。</span></p><p><span>RDB（Redis DataBase Snapshotting）是Redis的</span><strong><span>快照持久化</span></strong><span>，它将当前内存中的数据集快速地持久化到磁盘上。您可以设置RDB持久化间隔，每隔一段时间，Redis都会自动将当前数据集存储在磁盘上。</span><strong><span>RDB持久化非常快</span></strong><span>，但存在一些</span><strong><span>数据丢失的风险</span></strong><span>，在快照过程中只捕获内存中的数据集。如果Redis在快照之间停止，例如因为系统故障或用户干预，那么内存中的数据可能不完整。并且，如果快照间隔时间很长，则在快照期间更改的数据也可能丢失。</span></p><p><span>AOF（Append Only File）是Redis的追加式持久化，它</span><strong><span>记录每个写操作</span></strong><span>，并将其写入磁盘。这意味着</span><strong><span>AOF存储的是所有写操作的日志</span></strong><span>，并且可以在Redis启动时重放这些操作，以恢复其状态。 </span><strong><span>AOF持久化慢一些</span></strong><span>，但更</span><strong><span>安全</span></strong><span>，因为它记录了所有写操作，所以数据损失的风险更低。</span></p><p><span>可以选择只使用RDB持久化，也可以选择使用两种持久化方法。</span></p></blockquote><h4 id='常用数据类型'><code>常用数据类型</code></h4><blockquote><ol start='' ><li><span>String 字符串是Redis的最基本数据类型，可用于存储单个字符串值或键值对。</span></li><li><span>Hashes: 哈希是一种键值对的集合，用于存储对象或结构化数据。</span></li><li><span>Lists: 列表是一种链表数据结构，可以存储有序的数据。</span></li><li><span>Sets: 集合是一种无序的字符串集，用于存储不重复的元素。（共同关注）</span></li><li><span>Sorted Sets:有序集合是一种有序的字符串集 比Set多一个分数属性，根据字符串的分数对元素进行排序。（排行榜）</span></li></ol></blockquote><h4 id='缓存雪崩缓存穿透缓存击穿是什么如何解决'><code>缓存雪崩、缓存穿透、缓存击穿是什么，如何解决</code></h4><blockquote><p><span>&quot;缓存雪崩&quot;，&quot;缓存穿透&quot;和&quot;缓存击穿&quot;是缓存技术中常见的三个问题。</span></p><ul><li><span>缓存雪崩：当大量缓存同时失效时，会导致大量请求落在数据库上，造成数据库压力过大，从而服务器宕机。</span></li><li><span>缓存穿透：当请求的数据在数据库和缓存中都不存在（如：使用不存在的id查询某实体），此时缓存查不到请求会直接落在数据库上，数据库也查不到，就造成大量无效请求。</span></li><li><span>缓存击穿(热点key问题)：当一个业务复杂或访问量很高的key在缓存中过期时，大量请求同时落在数据库上，造成数据库压力过大，从而服务器宕机。</span></li></ul><p><span>以下是一些解决这三个问题的方法：</span></p><ul><li><span>缓存雪崩：设置超时时间的随机值: 设置缓存的超时时间不固定，采用随机值的方法来防止缓存雪崩。</span></li><li><span>缓存穿透：使用布隆过滤器预处理缓存中不存在的数据请求，避免直接落在数据库上，或缓存空值。</span></li><li><span>缓存击穿：使用分布式锁或者缓存预热来保护单个数据的并发请求，在缓存失效时及时重新加载数据到缓存中，或设置逻辑过期时间，让key永不过期。</span></li></ul></blockquote><h4 id='redis的内存管理机制及淘汰策略'><code>Redis的内存管理机制及淘汰策略</code></h4><blockquote><p><span>Redis使用称为Redis内存分配器的内存管理系统，该系统负责分配和释放Redis用于存储数据的内存块。当Redis使用的内存量接近由</span><code>maxmemory</code><span>配置选项设置的限制时，Redis将使用淘汰策略来确定从内存中删除哪些数据以释放空间。Redis支持几种淘汰策略：</span></p><ul><li><code>noeviction</code><span>：当达到内存限制时，Redis将拒绝存储新数据，并将返回错误。</span></li><li><code>allkeys-lru</code><span>：Redis将删除最近使用最少的键，不论它的类型或大小。</span></li><li><code>allkeys-random</code><span>：Redis将删除随机键。</span></li><li><code>volatile-lru</code><span>：Redis将删除具有过期设置的键中使用最少的键。</span></li><li><code>volatile-random</code><span>：Redis将删除具有过期设置的随机键。</span></li><li><code>volatile-ttl</code><span>：Redis将删除具有过期设置的剩余时间最短的键。</span></li><li><code>redis-lru</code><span>：Redis将删除所有类型键中使用最少的键。</span></li></ul></blockquote></div></div>
</body>
</html>